import {
	ControlVOBase,
	FormActionType,
	ICodeListItem,
	ICtrlActionResult,
	IEvent,
	IFormAbility,
	IFormController,
	IFormControllerParams,
	IFormDetailController,
	IFormModel,
	IFormStore,
	IHttpResponse,
	IParam,
	IViewLogicInput,
} from '@/core';
import {
	VerifyUtil,
	DataTypeUtil,
	deepCopy,
	verifyDynamicLogic,
	dateFormat,
	typeOf,
} from '@/core/utils';
import { FormDetailController } from './form-detail-controller';
import { DECtrlController } from './de-ctrl-controller';
import FormService from '@/core/modules/ctrl-service/form-service';

/**
 * 表单控制器
 *
 * @export
 * @class FormController
 * @extends {(DECtrlController<T | FormActionType, S, A>)}
 * @implements {IFormController<S, A>}
 * @template T
 * @template S
 * @template A
 */
export class FormController<T, S extends IFormStore, A extends IFormAbility>
	extends DECtrlController<T | FormActionType, S, A>
	implements IFormController<S, A>
{
	/**
	 * 表单模型
	 *
	 * @type {IFormModel}verifyDynamicLogic
	 * @memberof FormController
	 */
	protected declare readonly model: IFormModel;

	/**
	 * 部件服务
	 *
	 * @type {FormService<ControlVOBase>}
	 * @memberof FormController
	 */
	declare ctrlService: FormService<ControlVOBase>;

	/**
	 * 表单校验
	 *
	 * @type {Function}
	 * @memberof FormController
	 */
	formValidate!: Function;

	/**
	 * 处理部件初始化
	 *
	 * @protected
	 * @param {IFormControllerParams<FormActionType, IFormAbility>} params
	 * @memberof FormController
	 */
	protected processCtrlInit(
		params: IFormControllerParams<FormActionType, IFormAbility>
	) {
		super.processCtrlInit(params);
		this.formValidate = params.formValidate;
		Object.assign(this.store, {
			data: this.ctrlService.newControlVO({}),
			detailModel: {},
			valueRule: [],
		});
		this.initFormDetailModel();
	}

	/**
	 * 初始化表单成员模型
	 *
	 * @memberof FormController
	 */
	 private initFormDetailModel() {
		const { detailModel } = this.model;
		Object.values(detailModel).forEach((model: IParam) => {
            if (!model.parentIsRepeater) {
               const formDetailController: IFormDetailController = new FormDetailController({ model, form: this });
               this.setValueRules(formDetailController);
               this.store.detailModel[model.codeName] = formDetailController;
            }
		});
	}

	/**
	 * 初始化值规则
	 *
	 * @private
	 * @memberof FormController
	 */
	 protected setValueRules(controller: IFormDetailController) {
        const { valueRule } = this.model;
        const valueRules: IParam[] = [];
        const model: IParam = controller.getModel();
        // 系统值规则和属性值规则
        valueRule.forEach((rule: IParam) => {
            if (controller.name == rule.name) {
                if (rule.valueRuleType == 'SYSVALUERULE') {
                    // 正则校验
                    if (rule.ruleType == 'REG') {
                        valueRules.push({
                            trigger: ['onChange', 'onBlur'],
                            message: rule.ruleInfo,
                            pattern: rule.regExCode,
                        });
                    } else if (rule.ruleType == 'SCRIPT') {
                        // 脚本校验
                        valueRules.push({
                            trigger: ['onChange', 'onBlur'],
                            message: rule.ruleInfo,
                            validator: (verify: any, value: any, callback: Function) => {
                                if (this.store.data[rule.name]) {
                                    const data = this.store.data;
                                    const context = this.store.context;
                                    const viewParams = this.store.viewParams;
                                    try {
										controller.errorMessage = rule.scriptCode;
                                        eval(rule.scriptCode);
                                    } catch (error) {
                                        return false;
                                    }
                                }
								controller.errorMessage = '';
                                return true;
                            },
                        });
                    }
                } else if (rule.valueRuleType == 'DEFVALUERULE') {
                    valueRules.push({
                        trigger: ['onChange', 'onBlur'],
						message:rule.ruleInfo,
                        validator: (verify: any, value: any, callback: Function) => {
                            if (this.store.data[rule.name]) {
                                const { isPast, infoMessage } = VerifyUtil.verifyDeRules(
                                    rule.name,
                                    this.store.data,
                                    rule.condition
                                );
                                if (!isPast) {
									controller.errorMessage = infoMessage || rule.ruleInfo;
                                    return isPast;
                                }
                            }
							controller.errorMessage = '';
                            return true;
                        },
                    });
                }
            }
        })
        // 非空值规则
        valueRules.push({
            trigger: ['onChange', 'onBlur'],
            required: controller.required,
            message: model.caption + `${App.ts("widget.editform.mandatory")}`,
			validator: ( value: any, verify: any, callback: Function) => {
                if (verify.required) {
                    if (typeOf(value) == 'array') {
                        for (let index = 0; index < value.length; index++) {
                            if (!(value[index] || value[index] === 0)) {
								controller.errorMessage = `${model.captionItemName
									? this.store.data[
										model.captionItemName.toLowerCase()
									]
									: model.caption
								} ${App.ts("widget.editform.mandatory")}!`;
                                return false;
                            }
                        }
                    } else if (!(value || value === 0)) {
						controller.errorMessage = `
						${model.captionItemName
							? this.store.data[
								model.captionItemName.toLowerCase()
							]
							: model.caption
						} ${App.ts("widget.editform.mandatory")}!
					`
                        return Promise.reject(`
                            ${model.captionItemName
                                ? this.store.data[
                                    model.captionItemName.toLowerCase()
                                ]
                                : model.caption
                            } ${App.ts("widget.editform.mandatory")}!
                        `);
                    }
                }
				controller.errorMessage = '';
                return true;
            },
        })
        // 编辑器值规则
        if (model.editRules) {
            valueRule.push(...VerifyUtil.buildVerConditions(model.editRules));
        }
        controller.valueRules = valueRules;
    }

	/**
	 * 加载草稿
	 *
	 * @param {IParam} [opts={}]
	 * @return {*}  {Promise<void>}
	 * @memberof FormController
	 */
	async loadDraft(opts: IParam = {}): Promise<ICtrlActionResult> {
		return Promise.reject({ ok: false, data: this.getData(), rowData: null });
	}

	/**
	 * 表单执行数据行为之后
	 * @param {string} action 表单行为
	 * @param {string} data 行为数据
	 * @memberof FormController
	 */
	protected async afterFormAction(action: string, data: IParam) {}

	/**
	 * 设置表单项启用
	 *
	 * @protected
	 * @memberof FormController
	 */
	protected setFormEnableCond() {
		const { data } = this.store;
		Object.values(this.store.detailModel).forEach((item: IParam) => {
			if (Object.is(item.detailType, 'FORMITEM')) {
				switch (item.enableCond) {
					case 0:
						// 不启用
						item.disabled = true;
						break;
					case 1:
						// 新建
						item.disabled = data.srfuf != 0;
						break;
					case 2:
						// 更新
						item.disabled = data.srfuf != 1;
						break;
					case 3:
						// 启用
						item.disabled = false;
						break;
					default:
						break;
				}
			}
		});
	}

	/**
	 * 表单动态逻辑
	 *
	 * @protected
	 * @param {string} name
	 * @memberof FormController
	 */
	protected formDynamicLogic(name: string) {
		const { data } = this.store;
		const { detailModel } = this.model;
		Object.values(detailModel).forEach((item: IParam) => {
			item.groupLogics?.forEach((logic: IParam) => {
				let relatedNames = logic.relatedDetailNames || [];
				if (Object.is(name, '') || relatedNames.indexOf(name) != -1) {
					let ret = verifyDynamicLogic(data, logic);
					switch (logic.logicCat) {
						// 动态空输入，不满足则必填
						case 'ITEMBLANK':
							this.store.detailModel[item.name].required = !ret;
							this.changeRequiredValueRule(item.name, !ret);
							break;
						// 动态启用，满足则启用
						case 'ITEMENABLE':
							this.store.detailModel[item.name].disabled = !ret;
							break;
						// 动态显示，满足则显示
						case 'PANELVISIBLE':
							this.store.detailModel[item.name].visible = ret;
							break;
					}
				}
			});
		});
	}

	/**
	 * 必填值规则改变
	 *
	 * @param {string} name 表单项
	 * @param {boolean} required 必填
	 * @memberof FormController
	 */
	private changeRequiredValueRule(name: string, required: boolean) {
		this.store.valueRule[name]?.forEach((rule: IParam) => {
			if (rule.hasOwnProperty('required')) {
				rule.required = required;
			}
		});
	}

	/**
	 * 转化代码项文本
	 *
	 * @protected
	 * @memberof FormController
	 */
	protected async translateCodeListText() {
		const { data, context, viewParams } = this.store;
		const { detailModel } = this.model;
		const tempData = deepCopy(data);
		for (const key in tempData) {
			if (data.hasOwnProperty(key)) {
				if (
					detailModel[key] &&
					detailModel[key].convertToCodeItemText &&
					detailModel[key].codeListTag
				) {
					const codeListResult =
						await App.getAppCodeListHelper().getCodeListItems(
							detailModel[key].codeListTag,
							context,
							viewParams
						);
					if (codeListResult.ok) {
						const result = codeListResult.data;
						result.forEach((item: ICodeListItem) => {
							if (Object.is(item.value, tempData[key])) {
								tempData[key] = item.text;
							}
						});
					}
				}
			}
		}
		Object.assign(this.store.data, tempData);
	}

	/**
	 * 表单项更新
	 *
	 * @protected
	 * @param {string} name 表单项名称
	 * @memberof FormController
	 */
	protected async formItemUpdate(name: string) {
		const { detailModel } = this.model;
		const formItemUpdate = detailModel[name]?.formItemUpdate;
		if (formItemUpdate) {
			const context = deepCopy(this.store.context);
			const viewParams = deepCopy(this.store.viewParams);
			let data = this.store.data;
			try {
				if (formItemUpdate.customCode && formItemUpdate.scriptCode) {
					eval(formItemUpdate.scriptCode);
				} else {
					const response: IHttpResponse = await this.ctrlService.frontLogic(
						formItemUpdate.appDEMethod,
						context,
						{
							...this.store.data.$DO,
							viewParams: viewParams,
						}
					);
					if (response.success) {
						formItemUpdate.updateDetails?.forEach((detailsName: string) => {
							if (data.hasOwnProperty(detailsName.toLowerCase())) {
								Object.assign(data, {
									[detailsName.toLowerCase()]:
										response.data[detailsName.toLowerCase()],
								});
							}
						});
						await this.afterFormAction('formItemUpdate', data);
						this.executeFromDetailAbility({
							name: name,
							action: 'formItemUpdate',
							data: this.store.data,
						});
					}
				}
			} catch (error: any) {}
		}
	}

	/**
	 * 检验是否忽略输入值
	 *
	 * @protected
	 * @param {string} name 表单项名称
	 * @param {("before" | "change")} [step="change"] 步骤
	 * @return {*}  {boolean}
	 * @memberof FormController
	 */
	protected checkIgnoreInput(
		name: string,
		step: 'before' | 'change' = 'change'
	): boolean {
		const { detailModel } = this.store;
		const formDetail = detailModel[name];
		if (formDetail) {
			switch (formDetail.ignoreInput) {
				case 4:
					if (formDetail.disabled) {
						return true;
					}
					break;
			}
		}
		return false;
	}

	/**
	 * 重置表单项
	 *
	 * @protected
	 * @param {string} name 表单项名称
	 * @memberof FormController
	 */
	protected async resetFormItem(name: string) {
		const { detailModel } = this.model;
		for (const detailName in detailModel) {
			const detail = detailModel[detailName];
			if (detail.resetItemName && Object.is(name, detail.resetItemName)) {
				await this.handleFormValueChange(detail.name, null);
				if (detail.valueItemName) {
					await this.handleFormValueChange(detail.valueItemName, null);
				}
			}
		}
	}

	/**
	 * 设置新建默认值
	 *
	 * @protected
	 * @memberof FormController
	 */
	protected setCreateDefault(name?: string, item?: IParam) {
        const createDefaultItems = name ? this.store.detailModel[name]?.createDefaultItems : this.model.createDefaultItems;
        let data: any = name ? item : this.store.data;
		const { viewParams, context } = this.store;
		createDefaultItems?.forEach((item: IParam) => {
			const { createDV, createDVT, property, dataType, valueFormat } = item;
			if (createDV || createDVT) {
				switch (createDVT) {
					case 'CONTEXT':
						data[property] = viewParams[createDV];
						break;
					case 'SESSION':
						data[property] = context[createDV];
						break;
					case 'APPDATA':
						data[property] = context[createDV];
						break;
					case 'OPERATORNAME':
						data[property] = context['srfusername'];
						break;
					case 'OPERATOR':
						data[property] = context['srfuserid'];
						break;
					case 'CURTIME':
						data[property] = dateFormat(new Date(), valueFormat);
						break;
					case 'PARAM':
						data[property] =
							this.ctrlService.getRemoteCopyData()[property] || null;
						break;
					default:
						data[property] = DataTypeUtil.isNumber(dataType)
							? Number(createDV)
							: createDV;
						break;
				}
			}
		});
	}

	/**
	 * 处理表单值变化
	 *
	 * @param {string} name 表单项名称
	 * @param {*} value 表单项值
	 * @return {*}
	 * @memberof FormController
	 */
	protected async handleFormValueChange(
		name: string,
		value: any
	): Promise<void> {}

	/**
	 * 处理表单成员能力
	 *
	 * @protected
	 * @param {IEvent<string>} params 参数
	 * @memberof FormController
	 */
	protected executeFromDetailAbility(params: IEvent<string>) {
		const { detailModel } = this.store;
		Object.values(detailModel).forEach((detail: IParam) => {
			const ability = detail.getAbility();
			if (ability && ability.executeFormDetail) {
				ability.executeFormDetail(params);
			}
		});
	}

	/**
	 * 处理表单界面行为
	 *
	 * @param {MouseEvent} event 事件源
	 * @param {IViewLogicInput} logic 逻辑
	 * @memberof FormController
	 */
	private handleFormUIAction(event: MouseEvent, logic: IViewLogicInput): void {
		const { context, viewParams } = this.store;
		App.getViewLogicHelper().executeViewLogic(
			context,
			viewParams,
			this.getData(),
			event,
			this.getAbility(),
			logic
		);
	}

	/**
	 * 处理表单分组管理
	 *
	 * @param {string} name 表单分组名称
	 * @param {boolean} value 值
	 * @memberof FormController
	 */
	private handleFormGroupManage(name: string, value: boolean) {
		const formGroupDetail = this.store.detailModel[name];
		if (
			formGroupDetail.showMoreMode == 2 &&
			formGroupDetail.showMoreItems.length > 0
		) {
			const showMoreItems = formGroupDetail.showMoreItems;
			showMoreItems.forEach((itemName: string) => {
				this.store.detailModel[itemName].visible = value;
			});
		}
	}

	/**
	 * 设置表单成员能力
	 *
	 * @param {string} name
	 * @param {IParam} data
	 * @memberof FormController
	 */
	private setFormDetailAbility(name: string, data: IParam) {
		this.store.detailModel[name].setAbility(data);
	}

	/**
	 * 处理表单组件行为
	 *
	 * @param {IEvent<string>} actionParam 行为参数
	 * @memberof FormController
	 */
	public handleComponentAction(actionParam: IEvent<string>): void {
		const { name, action, data } = actionParam;
		switch (action) {
			case 'valueChange':
				this.handleFormValueChange(name, data);
				break;
			case 'formButtonAction':
				if(Object.is(data.actionType,'FIUPDATE')){
					this.formItemUpdate(data.logic?.name);
					break;
				}
				this.handleFormUIAction(data.event, data.logic);
				break;
			case 'formGroupAction':
				this.handleFormUIAction(data.event, data.logic);
				break;
			case 'formGroupManage':
				this.handleFormGroupManage(name, data);
				break;
			case 'componentInit':
				this.setFormDetailAbility(name, data);
				break;
			case 'editorClick':
				this.handleEditorClick(name, data);
				break;
			case 'editorFocus':
				this.handleEditorFocus(name, data);
				break;
			case 'editorBlur':
				this.handleEditorBlur(name, data);
				break;
		}
	}

	/**
	 * @description 表单编辑器点击事件
	 * @date 2023/02/03 10:02:48
	 * @param {string} name
	 * @param {*} data
	 * @memberof FormController
	 */
	public handleEditorClick(name: string, data: any) {
		console.log(name, data, 'click');
	}

	/**
	 * @description 表单编辑器聚焦事件
	 * @date 2023/02/03 10:02:24
	 * @param {string} name
	 * @param {*} data
	 * @memberof FormController
	 */
	public handleEditorFocus(name: string, data: any) {
		console.log(name, data, 'focus');
	}

	/**
	 * @description 表单编辑器失去焦点事件
	 * @date 2023/02/03 10:02:37
	 * @param {string} name
	 * @param {*} data
	 * @memberof FormController
	 */
	public handleEditorBlur(name: string, data: any) {
		console.log(name, data, 'blur');
	}

	/**
	 * 获取能力
	 *
	 * @return {*}  {IEditFormAbility}
	 * @memberof FormController
	 */
	getAbility(): A {
		return {
			...super.getAbility(),
			loadDraft: this.loadDraft.bind(this),
			formValidate: this.formValidate,
		};
	}
}
